require "./common.rb"

# print "Hello World"
puts "Hello World"
print "Another Hello World"
puts

# how to comment
=begin
here is some multi-line comment
as shown in here
=end

# use of variable/constant

# one of the typical "agreement" of ruby, where the difference between
# constant & variable is just the case of first alphabet
CONST_1 = 10
# CONST_1 = 15 # change constant will be warned, but NetBeans simply ban
const_fake = 11
const_fake = 150003
puts const_fake.to_s(16) # to_s(base) is really a well-designed API
puts const_fake.class
puts const_fake.kind_of?(Integer)
# special variable in ruby
puts $$ #$@, $., $_, $?, ... some global ones about the ruby environment
puts nil
puts self
puts
# scope of variable
var1 = "var1" # default is local variable as defined explicitly as "_var1"
puts defined? var1
_Var1 = "_Var1"
puts defined? _Var1
$var1 = "$var1"
puts defined? $var1
@@var1 = "@@var1" # class variable == "static" class member in JAVA
puts defined? @@var1
@var1 = "@var1" # instance variable == non-static class member in JAVA
puts defined? @var1
puts

# Conversion in between types of numbers
puts Integer(10.9339).kind_of?(Integer)
puts Integer(0b101011).kind_of?(Integer)
puts Integer("542353").kind_of?(Integer)
puts Float(3)
puts Float("34")
puts Float(0b110011)

#puts Integer(?e) # only available in ruby 1.8.x backwards
#puts "e".getbyte(0); # only available in ruby 1.9x onwards


# method
def addUp(arg1, arg2)
  result = arg1 + arg2
  #return result  # like in scala, the last variable will be returned by default
end
puts "result of addUp() is " + addUp(6,7).to_s(10)

def printAny(*args)
  args.each { |i| print i}  # |i| works like "this" in js closure
end
printAny("a", "b", "c")
puts

# alias a method
alias justPrint printAny
justPrint("e", "f", "g")
puts

# range. ".." & "...", many operations defined for Range is very much like scala
range1 = 1..10
range1.each { |i| print i.to_s(10) + "," }
puts
range1 = 1...10
range1.each { |i| print i.to_s(10) + "," }
puts
range2 = 'zza'..'zzd'
range2.each { |i| print i + "," }
puts
defer_range2 = range2.reject { |obj| obj == 'zzb' }
defer_range2.each { |item| print item + "," }
puts
puts range2.all? { |obj| obj.length > 3 }
puts range2 === 'zzc' # contains 'zzc'
# case check
score = 5
# case when syntax for 1.8.x only
#result = case score
#  when 1..5: "Failed"
#  when 6..10: "Good"
#end
result = case score
when 1..5 then "Failed"
when 6..10 then "Good"
end
puts result


# Array


days_week = Array.new
puts days_week.empty?
days_week[0] = 'abc'
puts days_week.empty?
puts days_week
puts
days_week = Array.new(7)
puts days_week.size
days_week[0] = 'Mon'
days_week[1] = 'Tue'
days_week[5] = 'Sat'
days_week[6] = 'Sun'
puts days_week.first
puts days_week.last
puts days_week.first(2)
puts

puts days_week[0,6]
puts days_week[4..6]
puts days_week[-1]
puts

days1 = Array.new(3)
days2 = Array.new(4)
days3 = days1 + days2 # the combining of array is combine by copy rather reference
days1[0] = 'Mon'
days1[1] = 'Tue'
days1[2] = 'Wed'
days2[0] = 'Thur'
days2[1] = 'Fri'
days2[2] = 'Sat'
days2[3] = 'Sun'
# puts days3 # result are all empty
days4 = days1 + days2 # days1/days2 itself will not be modified
printArray(days4) # result are full
days4 = days1.concat(days2)  # days1 itself has been modified too
printArray(days4) # same as above
puts
days5 = days2 + Array.new(0)
days5 << 'Thur' << 'Fri'
printArray(days5)
printArray(days2)
puts

# Advance array operations
linux_os = ["Suse","Redhat","Ubuntu","CentOS","Mandriva","Suse"]
os = ["Suse","Redhat","Windows XP","Windows 7", "MacOS","Solaris","AIX"]
printArray(linux_os | os)
printArray(linux_os & os)
printArray(linux_os - os)
printArray(linux_os.uniq) # won't change the org array
printArray(linux_os.uniq!) # will change the org array
puts
# pop & push
os.push("Debian")
printArray(os)
printArray(os.pop(2))
printArray(os)
# insert & delete & sort
numbers = [2,5,4,6,3,1,6,7,9,8]
numbers.insert(3, 10)
printArray(numbers)
numbers.delete_at(3)
printArray(numbers)
sortedNums = numbers.sort { |x,y| y <=> x }
printArray(sortedNums)
numbers.sort! { |x,y| x <=> y } # sort! will change the operation target
printArray(numbers)

# parellel assignments
a = 10
b = 20
c = 30
# above equivalent to
a, b, c = 10, 20, 30
printArray([a,b,c])
# and so it is useful to swapping value
a, b = b, a
printArray([a,b])

# Math object
printArray(Math.constants)
puts Math::E
puts Math::PI
puts Math.sqrt(2)


# OO programming
# the class definition, instance variable definition, getter/setter are
# alike scala very much, where a no param method don't need the "()"
class BankAccount
  def initialize(accountName)
    # constructor
    puts "initialize/constructor of BankAccount called"
    @accountName = accountName
  end

  def test_method
    puts "it is a test method of BankAccount"
  end

  # getter/setter
  def accountType
    @@accountType = "normal"
  end
  def accountType= (accountType)
    @@accountType = accountType
  end
  def accountName
    @accountName
  end
  def accountName= (accountName)
    @accountName = accountName
  end
end
# to new an instance, it is like scala using the companion object of a class
account1 = BankAccount.new("zhou.zhefu")
print account1.accountType
print "; "
print account1.accountName
puts
account1.accountName=("zhou.zhefu")
puts account1.accountName
account1.test_method
puts
# inheritance
class SnakeBankAccount < BankAccount
  def initialize(accountName)
    @accountLias = "Snake"
  end
  def accountLias
    @accountLias
  end
end
account2 = SnakeBankAccount.new("winnie.wong")
account2.test_method
puts account2.accountLias
puts

# case when
mycar = "Toyota"
result = case mycar
when "Toyota" then "shit"
when "Mercedes" then "good"
when "Bently" then "explendid"
else "no car at all"
end
puts result
puts

# loops, "while" loop no diff with other langs, "until" newly introduced
i = 0
until i > 3
  print i += 1
  print ","
end
puts
i = 0
puts i += 1 until i > 3 # "until" as statement modifier
#puts
# "for" loop and its variants
for i in 1..8 do # "do" is optional in here
  print i
  print ","
end
puts
for i in 1..8 do print i;print "," end # in single line "do" is not optional
puts
# "upto" loop, "downto" loop
5.upto(10) do
  | i |
  print i
  print ","
end
puts
5.upto(10) { |i| print i; print "," }
puts
15.downto(10) { |i| print i; print "," }
puts

# String process
myString = %&This is "my" PC& # to escape double quote
puts myString
myString = %(This is "my" PC) # to escape double quote
puts myString
myString = "This is \"my\" PC"
puts myString
# free format string, very good feature over other languages
myString = <<DOC
When the time is come
    no one can escape
 let's just embrace the new
            WOLRD
DOC
puts myString
# concatenating, all below are equivalent
myString = "i " + "love " + "Ruby"
myString = "i ""love ""Ruby"
myString = "i ".concat("love ").concat("Ruby")
puts myString
myString.freeze # after frozen, cannot do concatenating anymore
# myString.concat(" abc") # error here because assigning a frozen string
# access element
puts myString["Ruby"]
puts myString["Jeff"]
puts myString[2..5]
puts myString.index("love")
puts "Apple" <=> "apple" # <=> simply like "compareTo()" in JAVA
puts "Apple".casecmp("apple") # casecmp() is case insensitive compare
# changing section
string1 = "Welcome to JavaScript"
string1["JavaScript"] = "Ruby"
puts string1
string1 = "Welcome to JavaScript"
string1[8..10] = "Ruby"
puts string1
string1 = "Welcome to JavaScript"
string2 = string1.gsub("JavaScript", "Ruby") # will not change string1
print string1 + " ; " + string2
puts
string1.gsub!("JavaScript", "Ruby") # will change string1
puts string1
string1 = "Welcome to JavaScript"
string1.insert(3, "Ruby")
puts string1
string2 = string1 * 3 # repeat string content
puts string1 + " ; " + string2

# string to array
string1 = "abcdefg"
arr1 = string1.split
printArray(arr1)
string2 = "a,b,c,d,e,f"
arr2 = string2.split("/,/")
printArray(arr2)
puts

# case changing
string1 = "abcDe"
puts string1.upcase
puts string1.swapcase!
puts

# conversion
string1 = "1000"
puts string1.to_i(10)
symName = "myString"
puts symName.to_sym


# Filesystem
puts Dir.pwd
Dir.chdir("S:/Public/Jeff/test") do
  puts Dir.pwd
  puts Dir.entries(".") # list files under specific dir
  Dir.foreach(".") { |filename| print filename + "," }
  puts
  puts File.readable?("testRuby.txt")
  puts File.ctime("testRuby.txt")
  myFile = File.open("testRuby.txt")
  # puts myFile.readline
  # puts myFile.readline
  myFile.each { |line| puts line }
  myFile.close
end

# Date
require 'date' # the date lib must be imported before use
puts date = Date.new(2011, 9, 13)
puts DateTime.now
print date.day; print "/"; print date.month; print "/"; print date.year; puts


